//文件名: topology/topology.c
//
//描述: 这个文件实现一些用于解析拓扑文件的辅助函数 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

#include "topology.h"
#include "../common/constants.h"
#include "../utils/concurrent.h"

#define TOPOLOGY_FILE_ADDR "../topology/topology.dat"
#define NODE_INFO_FILE_ADDR "../config/network.config"
#define ADDR_STR_LRN 16

int is_inited=0;
int node_id=-1;
int node_num=-1;
int nbr_num=-1;
int edge_num=-1;
in_addr_t node_ip=-1;
node_t* node_list=NULL;
node_t* nbr_list=NULL;
edge_t* topology=NULL;

//**************************UNUSED API**************************
//这个函数返回指定主机的节点ID.
//节点ID是节点IP地址最后8位表示的整数.
//例如, 一个节点的IP地址为202.119.32.12, 它的节点ID就是12.
//如果不能获取节点ID, 返回-1.
int topology_getNodeIDfromname(char* hostname) 
{
  return 0;
}
//**************************UNUSED API**************************

void construct_node_list()
{
  FILE* file=fopen(NODE_INFO_FILE_ADDR,"r");
  if(file==NULL)
  {
    concurrent_printf_warning("%s file doesn't exit!\n",NODE_INFO_FILE_ADDR);
    exit(1);
  }

  for(int i=0;i<node_num;i++)
  {
    int nodeID;
    fscanf(file,"%d",&nodeID);

    char nodeIPstr[ADDR_STR_LRN];
    memset(nodeIPstr,0,sizeof(nodeIPstr));
    fscanf(file,"%s",nodeIPstr);
    
    in_addr_t nodeIP=-1;
    inet_aton(nodeIPstr,(struct in_addr*)&nodeIP);
    node_list[i].nodeID=nodeID;
    node_list[i].nodeIP=nodeIP;
    if(nodeID==node_id)node_ip=nodeIP;
  }
  fclose(file);
}

void construct_topology()
{
  FILE* file=fopen(TOPOLOGY_FILE_ADDR,"r");
  if(file==NULL)
  {
    concurrent_printf_warning("%s file doesn't exit!\n",NODE_INFO_FILE_ADDR);
    exit(1);
  }
  for(int i=0;i<edge_num;i++)
  {
    int nodeA,nodeB,cost;
    fscanf(file,"%d",&nodeA);
    fscanf(file,"%d",&nodeB);
    fscanf(file,"%d",&cost);
    topology[i].nodeA=nodeA;
    topology[i].nodeB=nodeB;
    topology[i].cost=cost;
  }
}

//必须在最后构建
void construct_nbr_list()
{
  int neighbourIndex=0;
  for(int i=0;i<edge_num;i++)
  {
    int nbrID=-1;

    if(topology[i].nodeA==node_id)
      nbrID=topology[i].nodeB;
    
    if(topology[i].nodeB==node_id)
      nbrID=topology[i].nodeA;
    
    if(nbrID!=-1){
      int j=0;
      for(;j<node_num;j++)
      {
        if(node_list[j].nodeID==nbrID)
            break;
      }
      nbr_list[neighbourIndex].nodeID=node_list[j].nodeID;
      nbr_list[neighbourIndex].nodeIP=node_list[j].nodeIP;
      neighbourIndex++;
    }
  }
}

int element_existed(int *arr,int size,int ele)
{
  for(int i=0;i<size;i++)
  {
    if(ele==arr[i])
      return 1;
  }
  return 0;
}

void topology_init()
{
  if(is_inited)return ;
  if(node_id==-1)
  {
    concurrent_printf("please input node id:");
    scanf("%d",&node_id);
  }

  FILE* file=fopen(TOPOLOGY_FILE_ADDR,"r");
  if(file==NULL)
  {
    concurrent_printf_warning("%s file doesn't exit!\n",TOPOLOGY_FILE_ADDR);
    fclose(file);
    exit(1);
  }

  int nodemap[MAX_NODE_NUM];
  edge_num=0;
  node_num=0;
  nbr_num=0;

  while(!feof(file))
  {
    int nodeA,nodeB,cost;
    fscanf(file,"%d",&nodeA);
    fscanf(file,"%d",&nodeB);
    fscanf(file,"%d",&cost);
    if(!element_existed(nodemap,node_num,nodeA))
    {
      nodemap[node_num]=nodeA;
      node_num++;
    }
    if(!element_existed(nodemap,node_num,nodeB))
    {
      nodemap[node_num]=nodeB;
      node_num++;
    }
    edge_num++;

    if(nodeA==node_id || nodeB==node_id)
      nbr_num++;
  }
  fclose(file);
  node_list=(node_t*)calloc(node_num,sizeof(node_t));
  nbr_list=(node_t*)calloc(nbr_num,sizeof(node_t));
  topology=(edge_t*)calloc(edge_num,sizeof(edge_t));
  construct_node_list();
  construct_topology();
  construct_nbr_list();
  is_inited=1;
}

//这个函数返回指定的IP地址的节点ID.
//如果不能获取节点ID, 返回-1.
int topology_getNodeIDfromip(struct in_addr* addr)
{
  if(!is_inited)topology_init();
  int ret=-1;
  for(int i=0;i<node_id;i++)
  {
    if(node_list[i].nodeIP==addr->s_addr){
        ret=node_list[i].nodeID;
        break;
    }
  }
  return ret;
}

//这个函数解析保存在文件topology.dat中的拓扑信息.
//返回一个动态分配的数组, 它包含重叠网络中所有节点的ID. 
int* topology_getNodeArray()
{
  if(!is_inited)topology_init();
  int* node_arr=(int*)calloc(node_num,sizeof(int));
  for(int i=0;i<node_num;i++)
  {
    node_arr[i]=node_list[i].nodeID;
  }
  return node_arr;
}

//这个函数解析保存在文件topology.dat中的拓扑信息.
//返回一个动态分配的数组, 它包含所有邻居的节点ID.
int* topology_getNbrArray()
{ 
  if(!is_inited)topology_init();
  int* nbr_array=(int*)calloc(nbr_num,sizeof(int));
  for(int i=0;i<nbr_num;i++)
  {
    nbr_array[i]=nbr_list[i].nodeID;
  }
  return nbr_array;
}

//这个函数返回本机的节点ID
//如果不能获取本机的节点ID, 返回-1.
int topology_getMyNodeID()
{
  if(!is_inited)topology_init();
  return node_id;
}

//这个函数解析保存在文件topology.dat中的拓扑信息.
//返回邻居数.
int topology_getNbrNum()
{
  if(!is_inited)topology_init();
  return nbr_num;
}

//这个函数解析保存在文件topology.dat中的拓扑信息.
//返回重叠网络中的总节点数.
int topology_getNodeNum()
{ 
  if(!is_inited)topology_init();
  return node_num;
}

//这个函数解析保存在文件topology.dat中的拓扑信息.
//返回指定两个节点之间的直接链路代价. 
//如果指定两个节点之间没有直接链路, 返回INFINITE_COST.
unsigned int topology_getCost(int fromNodeID, int toNodeID)
{
  if(!is_inited)topology_init();
  if(fromNodeID==toNodeID)return 0;

  int cost=INFINITE_COST;
  for(int i=0;i<edge_num;i++)
  {
    if((topology[i].nodeA==fromNodeID && topology[i].nodeB==toNodeID) ||
       (topology[i].nodeB==fromNodeID && topology[i].nodeA==toNodeID))
       {
         cost=topology[i].cost;
         break;
       }
  }
  return cost;
}

in_addr_t topology_getNodeIPfromid(int id){
  if(!is_inited)topology_init();

  in_addr_t ret=-1;
  for(int i=0;i<node_num;i++)
  {
    if(node_list[i].nodeID==id)
    {
      ret=node_list[i].nodeIP;
      break;
    }
  }
  return ret;
}


in_addr_t topology_getMyNodeIP(){
  if(!is_inited)topology_init();
  return node_ip;
}
